import {decrypt, encrypt, isNull} from "@/utils";

interface StorageData {
    value: any
    expire: number | null
}

const DEFAULT_CACHE_TIME = 1000 * 60 * 60 * 24 * 7;

export class StorageHelpers {
    private readonly keyPrefix: string
    private readonly storage: Storage

    constructor(keyPrefix: string, storage: Storage) {
        this.keyPrefix = keyPrefix;
        this.storage = storage;
    }

    private buildKey(key: string): string {
        return `${this.keyPrefix}.${key}`
    }

    set<T>(key: string, value: T, expire: number | null = DEFAULT_CACHE_TIME): T {
        const storageData: StorageData = {value, expire: expire ? new Date().getTime() + expire : null};
        this.storage.setItem(this.buildKey(key), encrypt(storageData));
        return value;
    }

    private getData(key: string): StorageData | null {
        const cipherText = this.storage.getItem(this.buildKey(key));
        if (cipherText === null) {
            return null;
        }
        const storageData: StorageData = decrypt(cipherText);
        if (storageData.expire && storageData.expire < new Date().getTime()) {
            this.storage.removeItem(this.buildKey(key));
            return null;
        }
        return storageData;
    }

    get<T>(key: string): T | null {
        const storageData = this.getData(key);
        return storageData ? storageData.value : null;
    }

    getOrDefault<T>(key: string, defaultValue: T): T {
        const storageData = this.getData(key);
        return isNull(storageData) ? defaultValue : storageData?.value;
    }

    has(key: string): boolean {
        return this.getData(key) !== null
    }

    remove(key: string) {
        this.storage.removeItem(this.buildKey(key));
    }

    getExpire(key: string): number | null {
        const storageData = this.getData(key);
        return storageData ? storageData.expire : null;
    }

    clear() {
        this.storage.clear();
    }

}
